package org.aceor.mddal.gateway.sqlparser.visitor;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlSelectGroupByExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.google.common.base.Strings;
import org.aceor.mddal.common.sqlparser.result.object.Column;
import org.aceor.mddal.common.sqlparser.result.object.GroupByColumn;
import org.aceor.mddal.common.sqlparser.result.object.Limit;
import org.aceor.mddal.common.sqlparser.result.object.OrderByColumn;
import org.aceor.mddal.common.sqlparser.util.SQLParserUtil;

import java.util.List;

import static org.aceor.mddal.common.sqlparser.result.object.OrderByColumn.OrderByType;

/**
 * Created by lxue on 16/3/21.
 */
public class MysqlSelectVisitor extends AbstractMysqlVisitor {

    @Override
    protected void printSelectList(final List<SQLSelectItem> selectList) {
        super.printSelectList(selectList);
        //注册ColumnAppendToken对象,如果需要增补列,这个对象将起作用
        registerColumnAppendToken();
    }

    @Override
    public boolean visit(final SQLAggregateExpr sqlAggregateExpr) {
        return super.visit(sqlAggregateExpr);
    }

    @Override
    public boolean visit(final MySqlSelectGroupByExpr mySqlSelectGroupByExpr) {
        //处理同Orderby
        getParseContext().addGroupByColumn(buildGroupByColumn(mySqlSelectGroupByExpr));
        return super.visit(mySqlSelectGroupByExpr);
    }

    private GroupByColumn buildGroupByColumn(MySqlSelectGroupByExpr expr) {
        GroupByColumn groupByColumn = new GroupByColumn();
        groupByColumn.setOrderByType(OrderByType.valueof(expr.getType()));
        Column column = SQLParserUtil.buildColumnIgnoreAlias(expr.getExpr(), getParseContext().getSqlParsedResult().routeContext.getTables());
        groupByColumn.setName(column.getName());
        Column selectColumn = getParseContext().findSelectColumn(column);
        if (null == selectColumn) {
            //增补列
            getSQLBuilder().appendColumn(column.getName());
        } else {
            if (!Strings.isNullOrEmpty(selectColumn.getAlias())) {
                groupByColumn.setAlias(selectColumn.getAlias());
            }
        }
        return groupByColumn;
    }

    @Override
    public boolean visit(final MySqlSelectQueryBlock.Limit limitExpr) {
        print("LIMIT ");
        int offset = 0;
        if (null != limitExpr.getOffset()) {
            if (limitExpr.getOffset() instanceof SQLNumericLiteralExpr) {
                offset = ((SQLNumericLiteralExpr) limitExpr.getOffset()).getNumber().intValue();
                print("0, ");
            } else {
                offset = ((Number) getParameters().get(((SQLVariantRefExpr) limitExpr.getOffset()).getIndex())).intValue();
                getParameters().set(((SQLVariantRefExpr) limitExpr.getOffset()).getIndex(), 0);
                print("?, ");
            }
        }
        int rowCount;
        if (limitExpr.getRowCount() instanceof SQLNumericLiteralExpr) {
            rowCount = ((SQLNumericLiteralExpr) limitExpr.getRowCount()).getNumber().intValue();
            print(rowCount + offset);
        } else {
            rowCount = ((Number) getParameters().get(((SQLVariantRefExpr) limitExpr.getRowCount()).getIndex())).intValue();
            getParameters().set(((SQLVariantRefExpr) limitExpr.getRowCount()).getIndex(), rowCount + offset);
            print("?");
        }
        getParseContext().getSqlParsedResult().mergeContext.setLimit(new Limit(offset, rowCount));
        return false;
    }

    @Override
    public boolean visit(final SQLOrderBy orderBy) {
        /**
         * 1. 收集order by信息(如果select列有别名,可能需要设置orderByColumnAlias)
         * 2. 如果select列不存在orderby字段就进行补列操作
         */
        List<SQLSelectOrderByItem> orderByItems = orderBy.getItems();
        for (SQLSelectOrderByItem orderByItem : orderByItems) {
            getParseContext().addOrderByColumn(buildOrderByColumn(orderByItem));
        }
        return super.visit(orderBy);
    }


    private OrderByColumn buildOrderByColumn(SQLSelectOrderByItem orderByItem) {
        OrderByColumn orderByColumn = new OrderByColumn();
        orderByColumn.setOrderByType(OrderByType.valueof(orderByItem.getType()));
        Column column = SQLParserUtil.buildColumnIgnoreAlias(orderByItem.getExpr(), getParseContext().getSqlParsedResult().routeContext.getTables());
        orderByColumn.setName(column.getName());
        Column selectColumn = getParseContext().findSelectColumn(column);
        if (null == selectColumn) {
            //增补列
            getSQLBuilder().appendColumn(column.getName());
        } else {
            if (!Strings.isNullOrEmpty(selectColumn.getAlias())) {
                orderByColumn.setAlias(selectColumn.getAlias());
            }
        }
        return orderByColumn;
    }

    @Override
    public boolean visit(final SQLSelectItem sqlSelectItem) {
        //存储select中Column
        Column column;
        SQLExpr expr = sqlSelectItem.getExpr();
        if (expr instanceof SQLAllColumnExpr) {
            column = Column.allColumn;
        } else if (expr instanceof SQLIdentifierExpr) {
            column = new Column(((SQLIdentifierExpr) expr).getName());
        } else if (expr instanceof SQLPropertyExpr) {
            column = new Column(((SQLPropertyExpr) expr).getName());
        } else {
            throw new IllegalArgumentException();
        }
        if (!Strings.isNullOrEmpty(sqlSelectItem.getAlias())) {
            column.setAlias(sqlSelectItem.getAlias());
        }
        getParseContext().addSelectColumn(column);
        return super.visit(sqlSelectItem);
    }
}

